package com.ccp.dev.qbdms.expimp.util;

import com.alibaba.fastjson.JSONObject;
import com.ccp.dev.core.poi.excel.reader.DataEntity;
import com.ccp.dev.core.poi.excel.reader.FieldEntity;
import com.ccp.dev.core.poi.excel.reader.TableEntity;
import com.ccp.dev.core.util.AppUtil;
import com.ccp.dev.core.util.BeanUtils;
import com.ccp.dev.core.util.StringUtil;
import com.ccp.dev.qbdms.expimp.annotation.ImpAnnotation;
import com.ccp.dev.system.model.Dictionary;
import com.ccp.dev.system.service.DictionaryService;

import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

/**
 * 导入工具类
 */
public abstract class AbstractImpUtil {
    /**
     * 解析数据到model
     * @param tableEntity excel数据表
     * @param t 需要转换到的modelClass
     * @return map
     * @throws IllegalAccessException 异常
     * @throws InstantiationException 异常
     * @throws NoSuchFieldException 异常
     */
    public Map<String, Object> reverseModels(TableEntity tableEntity, Class<?> t) throws IllegalAccessException, NoSuchFieldException, InstantiationException {
        //获取主表sheetName
        String sheetName = tableEntity.getName();
        ImpAnnotation clsAnnotation = t.getAnnotation(ImpAnnotation.class);
        String description = "";
        if(null != clsAnnotation && StringUtil.isNotEmpty(clsAnnotation.description())){
            description = clsAnnotation.description();
        }else{
            description = t.getSimpleName();
        }
        if(!description.equals(sheetName)){
            Map<String,Object> retMap = new HashMap<>();
            retMap.put("msg","导入模板错误! 导入失败! 请确认后重新操作。");
            retMap.put("instList",new ArrayList<>());
            return retMap;
        }
        return this.reverseModels(tableEntity,t,"");
    };

    /**
     * 解析数据到model
     * @param tableEntity excel数据表
     * @param t 需要转换到的modelClass
     * @param pid 上级id
     * @return map
     * @throws IllegalAccessException 异常
     * @throws InstantiationException 异常
     * @throws NoSuchFieldException 异常
     */
    private Map<String, Object> reverseModels(TableEntity tableEntity, Class t, String pid) throws IllegalAccessException, InstantiationException, NoSuchFieldException {
        List<DataEntity> rowDataEntityList = tableEntity.getDataEntityList();
        List<TableEntity> subTableEntityList = tableEntity.getSubTableEntityList();
        //增加行号
        Map<Integer,Integer> rowMapping = new HashMap<>();
        //判断是否有子数据
        if(StringUtil.isNotEmpty(pid)){
            List<DataEntity> allRow = new ArrayList<>();
            AtomicInteger rowNum = new AtomicInteger(1);
            rowDataEntityList.forEach(a->{
                rowNum.set(rowNum.get()+1);
                long num = a.getFieldEntityList().stream().filter(b->b.getIsKey().equals(FieldEntity.IS_KEY)&&b.getValue().equals(pid)).count();
                if(num>0L){
                    allRow.add(a);
                    rowMapping.put(a.hashCode(),rowNum.get());
                }
            });
            if(allRow.isEmpty()){
                Map<String,Object> retMap = new HashMap<>();
                retMap.put("msg","");
                retMap.put("instList",allRow);
                return retMap;
            }else{
                rowDataEntityList = allRow;
            }
        }
        //获取sheetName
        String sheetName = tableEntity.getName();
        //获取当前类的所有字段
        Field[] fields = AuxiliaryUtil.getAllField(t);
        //过滤出所有带有注解的字段
        List<Field> fieldList = new ArrayList<>();
        for(Field field : fields){
            ImpAnnotation fieldAnnotation = field.getAnnotation(ImpAnnotation.class);
            if (BeanUtils.isNotEmpty(fieldAnnotation)) {
                fieldList.add(field);
            }
        }
        StringBuilder sb = new StringBuilder();
        List<Object> list = new ArrayList<>();
        int i=1;
        for(DataEntity dataEntity : rowDataEntityList){
            if(StringUtil.isNotEmpty(pid)){
                i = rowMapping.get(dataEntity.hashCode());
            }else{
                i++;
            }
            boolean isAdd = true;
            Object instance = t.newInstance();
            List<FieldEntity> fieldEntityList = dataEntity.getFieldEntityList();
            for(Field field : fieldList){
                Class<?> type = field.getType();
                ImpAnnotation fieldAnnotation = field.getAnnotation(ImpAnnotation.class);
                String description = fieldAnnotation.description();
                String jsonParseStr = fieldAnnotation.jsonParse();
                boolean isRequired = fieldAnnotation.isRequired();
                boolean isSubTable = fieldAnnotation.isSubTable();
                String dicKey = fieldAnnotation.dicKey();
                field.setAccessible(true);
                //取到当前行的主键值
                List<FieldEntity> pkFieldEntity = fieldEntityList.stream().filter(a->a.getIsKey().equals(FieldEntity.IS_KEY)).collect(Collectors.toList());
                //如果是子表
                if(isSubTable){
                    boolean isArray = false;
                    if(type.isArray()){
                        type = type.getComponentType();
                        isArray = true;
                    }else if(Collection.class.isAssignableFrom(type)){
                        Type genericType = field.getGenericType();
                        if (genericType instanceof ParameterizedType) {
                            ParameterizedType pt = (ParameterizedType) genericType;
                            type = (Class<?>)pt.getActualTypeArguments()[0];
                        }
                    }
                    if(!pkFieldEntity.isEmpty()){
                        FieldEntity fieldEntity = pkFieldEntity.get(0);
                        //取到主键值
                        String pidValue = fieldEntity.getValue();
                        //取到子表sheet
                        ImpAnnotation clsAnnotation = type.getAnnotation(ImpAnnotation.class);
                        if(null != clsAnnotation && StringUtil.isNotEmpty(clsAnnotation.description())){
                            description = clsAnnotation.description();
                        }else{
                            description = type.getSimpleName();
                        }
                        String finalDesc = description;
                        List<TableEntity> tableEntityList = subTableEntityList.stream().filter(a->finalDesc.equals(a.getName())).collect(Collectors.toList());
                        if(!tableEntityList.isEmpty()){
                            Map<String, Object> map =  reverseModels(tableEntityList.get(0),type,pidValue);
                            String msg = map.get("msg").toString();
                            sb.append(msg);
                            if(isArray){
                                field.set(instance,((ArrayList)map.get("instList")).toArray());
                            }else{
                                field.set(instance,map.get("instList"));
                            }
                        }
                    }
                }else{
                    int j=0;
                    for(FieldEntity fieldEntity : fieldEntityList){
                        j++;
                        if(fieldEntity.getName().equals(description)){
                            String value = fieldEntity.getValue();
                            if(StringUtil.isEmpty(value)){
                                if(isRequired){
                                    sb.append(sheetName+": 第"+i+"行,第"+j+"列【"+description+"】不能为空！</br>");
                                    isAdd = false;
                                }
                            }else{
                                //增加自定义验证
                                ReturnType returnType = customValidation(field.getName(),value);
                                if(null != returnType){
                                    if(StringUtil.isEmpty(returnType.getMsg())){
                                        if(StringUtil.isNotEmpty(returnType.getNewValue())){
                                            field.set(instance,convertByType(type.getName(),returnType.getNewValue()));
                                        }
                                    }else{
                                        sb.append(sheetName+": 第"+i+"行,第"+j+"列 【"+description+"】"+returnType.getMsg()+"</br>");
                                        isAdd = false;
                                    }
                                }else{
                                    if(Date.class.isAssignableFrom(type)){
                                        String dataFormat = fieldAnnotation.format();
                                        Date date = null;
                                        try {
                                            date = new SimpleDateFormat(dataFormat).parse(value.replaceAll(",",""));
                                        } catch (ParseException e) {
                                            sb.append(sheetName+": 第"+i+"行,第"+j+"列【"+description+"】时间格式错误！</br>");
                                            isAdd = false;
                                        }
                                        field.set(instance,date);;
                                    }else if(StringUtil.isNotEmpty(jsonParseStr)){
                                        JSONObject jsonParse = JSONObject.parseObject(jsonParseStr);
                                        Object formtValue = jsonParse.get(value);
                                        if(BeanUtils.isNotEmpty(formtValue)){
                                            field.set(instance,convertByType(type.getName(),formtValue.toString()));
                                        }else{
                                            sb.append(sheetName+": 第"+i+"行,第"+j+"列【"+description+"】非法的值！</br>");
                                            isAdd = false;
                                        }
                                    }else if(StringUtil.isNotEmpty(dicKey)){
                                        DictionaryService dictionaryService = AppUtil.getBean(DictionaryService.class);
                                        List<Dictionary> dictionaryList = dictionaryService.getByNodeKey(dicKey);
                                        if(!dictionaryList.isEmpty()){
                                            List<Dictionary> oneDic = dictionaryList.stream().filter(a->a.getItemName().equals(value)).collect(Collectors.toList());
                                            if(!oneDic.isEmpty() && StringUtil.isNotEmpty(oneDic.get(0).getItemValue())){
                                                field.set(instance,convertByType(type.getName(),oneDic.get(0).getItemValue()));
                                            }else{
                                                sb.append(sheetName+": 第"+i+"行,第"+j+"列【"+description+"】非法的值！</br>");
                                                isAdd = false;
                                            }
                                        }
                                    }else{
                                        field.set(instance,convertByType(type.getName(),value));
                                    }
                                }
                            }
                            break;
                        }
                    }
                }
            }
            if(isAdd){
                list.add(instance);
            }
        }
        Map<String,Object> retMap = new HashMap<>();
        retMap.put("msg",sb.toString());
        retMap.put("instList",list);
        return retMap;
    }

    /**
     * 将字符串数据按照指定的类型进行转换。
     *
     * @param typeName 实际的数据类型
     * @param value    字符串值。
     * @return Object
     */
    private static Object convertByType(String typeName, String value) {
        Object o = null;
        if ("int".equals(typeName) || Integer.class.getName().equals(typeName)) {
            o = Integer.parseInt(value);
        } else if ("short".equals(typeName) || Short.class.getName().equals(typeName)) {
            o = Short.parseShort(value);
        } else if ("long".equals(typeName) || Long.class.getName().equals(typeName)) {
            o = Long.parseLong(value);
        } else if ("float".equals(typeName) || Float.class.getName().equals(typeName)) {
            if(value.contains(",")){
                value = value.replaceAll(",","");
            }
            o = Float.parseFloat(value);
        } else if ("double".equals(typeName) || Double.class.getName().equals(typeName)) {
            if(value.contains(",")){
                value = value.replaceAll(",","");
            }
            o = Double.parseDouble(value);
        } else if ("boolean".equals(typeName) || Boolean.class.getName().equals(typeName)) {
            o = Boolean.parseBoolean(value);
        } else if ("java.lang.String".equals(typeName) || String.class.getName().equals(typeName)) {
            o = value;
        } else if ("java.math.BigDecimal".equals(typeName) || BigDecimal.class.getName().equals(typeName)) {
            if(value.contains(",")){
                value = value.replaceAll(",","");
            }
            o = new BigDecimal(value);
        } else {
            o = value;
        }
        return o;
    }

    /**
     *  可以自定义验证
     * @param fieldName  字段名称
     * @param fieldValue 导入进来的value值
     * @return true 验证通过  false 验证失败
     */
    public abstract ReturnType customValidation(String fieldName ,  String fieldValue);

    /**
     * 自定义返回类
     * msg 不为空就代表有异常
     * msg为空 并且newValue 有值就会将新值赋值到model中
     */
    public class ReturnType{
        String msg;
        String newValue;

        public String getMsg() {
            return msg;
        }

        public void setMsg(String msg) {
            this.msg = msg;
        }

        public String getNewValue() {
            return newValue;
        }

        public void setNewValue(String newValue) {
            this.newValue = newValue;
        }
    }
}
